package org.quickjsf.core.base.controller.support;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;

import org.apache.commons.lang3.StringUtils;
import org.primefaces.context.RequestContext;
import org.primefaces.event.CloseEvent;
import org.primefaces.model.MenuModel;
import org.quickjsf.common.util.DomainUtil;
import org.quickjsf.common.util.FacesUtil;
import org.quickjsf.core.annotations.MappingRelation;
import org.quickjsf.core.base.QuickJsfContainer;
import org.quickjsf.core.base.controller.IEditable;
import org.quickjsf.core.base.viewmodel.support.EditableViewModelSupport;
import org.quickjsf.core.annotations.MRelation.RELATION;
/**
 * 可编辑的表单Controller抽象实现
 * @author weird
 *
 */
public abstract class EditableDTPanelSupport<T> extends AbsDTPanelSupport<T> {

	private EditableViewModelSupport<T> editableViewModel;
	
	public static final String EDIT_FORM_ID = "edit_form";
	
	public EditableDTPanelSupport(EditableViewModelSupport<T> editableViewModel) {
		this.editableViewModel = editableViewModel;
	}
	
	public final String getFullEditFormId() {
		StringBuffer fullEditFormId = new StringBuffer();
		fullEditFormId.append(getBaseDTPanelController().getDatatablePanelClientId());
		fullEditFormId.append(FacesUtil.getSeparatorChar());
		fullEditFormId.append(EDIT_FORM_ID);
		
		return fullEditFormId.toString();
	}
	
	public void addEditableMenuModel(MenuModel menuModel) {
		menuModel.addMenuItem(getBaseDTPanelController().createSimpleMenuItem("menu_item_add", "新增",
			"javascript:showEditFormDlg("+getBaseDTPanelController().getDatatablePanelClientId()+");", "ui-icon-plusthick"));
		menuModel.addMenuItem(getBaseDTPanelController().createActionMenuItem("menu_item_edit", "编辑",
			"#{"+getBaseDTPanelController().getManageBeanName()+".editableDTPanelSupport.setUpdateRow}", "ui-icon-pencil", 
			null, "updatedCallback(xhr, status, args, "+getBaseDTPanelController().getDatatablePanelClientId()+");", null));
		menuModel.addMenuItem(getBaseDTPanelController().createActionMenuItem("menu_item_del", "删除", "#{"+getBaseDTPanelController().getManageBeanName()+".delete}",
			"ui-icon-trash", null, "showFilterLabel("+getBaseDTPanelController().getDatatablePanelClientId()+");", null));
	}
	
	/**
	 * 重置实体表单数据
	 * @param event
	 * @throws Exception
	 */
	public void resetEntityForm(CloseEvent event) throws Exception {
		RequestContext.getCurrentInstance().reset(event.getComponent().getClientId());  
		editableViewModel.resetEntity();
	}
	
	public void save(IEditable<T> editableCallback) throws Exception {
		boolean isOk = true;
		FacesMessage msg = null;  
		RequestContext requestContext = RequestContext.getCurrentInstance();  
		try {
	    	if (DomainUtil.getFieldIdValue(editableViewModel.getEntity()) == null) {
	    		setOneToOneRelation();
	    		editableCallback.onAddNew(editableViewModel.getEntity(), requestContext);
	    		getBaseDTPanelController().resetDataTable();
//	    		editableViewModel.resetSearchEntity(); 
//	    		editableViewModel.getDataModel().setCriterions(null);
	    	} else {
	    		editableCallback.onEdit(editableViewModel.getEntity(), requestContext);
	    	}
//	    	editableViewModel.resetEntity(); 
			msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "保存成功", "数据已成功保存."); 
			//update dataTable
			requestContext.update(getBaseDTPanelController().getFullDataTableId());
		} catch (Exception e) {
			isOk = false;
			e.printStackTrace();
			msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "保存失败", "保存数据时发生错误出错.原因："+e.getMessage()); 
		}
		
		requestContext.addCallbackParam("success", isOk); 
		FacesContext.getCurrentInstance().addMessage(null, msg); 
	}
	
	
	private void setOneToOneRelation() throws Exception {
		T entity = editableViewModel.getEntity();
		List<MappingRelation> relations = getBaseDTPanelController()
				.getQuickJsfContainer().getRelationMap().get(entity.getClass().getSimpleName());
		
		if (relations != null) {
			for (MappingRelation mappingRelation : relations) {
				if (mappingRelation.getRelation().equals(RELATION.ONE_TO_ONE)) {
					// get another entity instance;
					Object instance = entity.getClass().getDeclaredMethod("get"
							+StringUtils.capitalize(mappingRelation.getSource())).invoke(entity);
					// set this entity to another entity instance
					instance.getClass().getDeclaredMethod("set"
							+StringUtils.capitalize(mappingRelation.getMappedBy()), entity.getClass()).invoke(instance, entity);
				}
			}
		}
	}

	/**
	 * 设置选中行数据到实体中
	 * @param actionEvent
	 */
	public void setUpdateRow(ActionEvent actionEvent) {
		RequestContext requestContext = RequestContext.getCurrentInstance();  
		FacesMessage msg = null;  
		boolean success = false; 
		
		if (editableViewModel.getDTPanelViewModel().getSelectdEntity() == null) {
        	success = false;  
            msg = new FacesMessage(FacesMessage.SEVERITY_WARN, "警告", "该操作需要先选中一行数据."); 
            FacesContext.getCurrentInstance().addMessage(null, msg); 
		} else {
			success = true;  
			try {
				editableViewModel.setSelectedValToEntity();
				editableViewModel.getDTPanelViewModel().setSelectdEntity(null);
				//success update editForm
				requestContext.update(getFullEditFormId());
			} catch (Exception e) {
				e.printStackTrace();
				success = false;
				msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "错误", "获取数据时发生异常，固原：" + e.getMessage()); 
		        FacesContext.getCurrentInstance().addMessage(null, msg); 
			}
		}
		
		requestContext.addCallbackParam("success", success); 
	}
	
	public void delete(IEditable<T> editableCallback) {
        FacesMessage msg = null;  
        boolean isOk = true;  
         
		if (editableViewModel.getDTPanelViewModel().getSelectdEntity() == null) {
	    	isOk = false;  
	    	msg = new FacesMessage(FacesMessage.SEVERITY_WARN, "警告", "该操作至少需要选择一行数据."); 
		} else {
			try {
				editableCallback.onDelete(editableViewModel.getDTPanelViewModel().getSelectdEntity());
			} catch (Exception e) {
				isOk = false;  
				msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "删除失败", "删除数据时出错.原因："+e.getMessage()); 
			}
			if (isOk) {
				//success update editForm
				RequestContext.getCurrentInstance().update(getBaseDTPanelController().getFullDataTableId());
				msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "删除成功", "数据已成功删除.");
			}
		}
          
        FacesContext.getCurrentInstance().addMessage(null, msg);  
	}
	
	/**************************************多表关联支持*******************************************/
	@SuppressWarnings("unchecked")
	public void onAddRow(ActionEvent event) throws Exception {
		T entity = editableViewModel.getEntity();
		MappingRelation mappingRelation = getDtEntityCls();
		Object instance = mappingRelation.getTargetEntity().newInstance();
		
		//set entity to instance
		instance.getClass().getDeclaredMethod("set"+StringUtils.capitalize(mappingRelation.getMappedBy())
				 ,entity.getClass()).invoke(instance, entity);
		
		// add the instance to list
		Collection collection = (Collection) entity.getClass().getDeclaredMethod("get"
				+ StringUtils.capitalize(mappingRelation.getSource())).invoke(entity);
		collection.add(instance);
	}
	
	@SuppressWarnings("unchecked")
	public void onDelRow(ActionEvent event) throws Exception {
		String _selectedDtRows = FacesUtil.getRequestParameter("selected_dt_rows");
		RequestContext.getCurrentInstance().update(getBaseDTPanelController().getFullMsgGrowlId());
		
		if (StringUtils.isEmpty(_selectedDtRows)) {
			 FacesContext.getCurrentInstance().addMessage(null,
					 new FacesMessage(FacesMessage.SEVERITY_WARN, "警告", "该操作至少需要选择一行数据.")); 
			 
			 return;
		}
		String[] selectedDtRows = _selectedDtRows.split(",");
		
		T entity = editableViewModel.getEntity();
		MappingRelation mappingRelation = getDtEntityCls();
		
		Collection collection = (Collection) entity.getClass().getDeclaredMethod("get"
				+StringUtils.capitalize(mappingRelation.getSource())).invoke(entity);
		
		if (!(collection instanceof List)) {
			throw new RuntimeException(entity.getClass()+"."+"get"
					+StringUtils.capitalize(mappingRelation.getSource())+" must return list collection.");
		}
		
		//remove the a row instance from list
		List removeObjs = new ArrayList();
		for (String index : selectedDtRows) {
			removeObjs.add(((List)collection).get(Integer.valueOf(index).intValue()));
		}
		collection.removeAll(removeObjs);
	}
	
	private MappingRelation getDtEntityCls() {
		String className = FacesUtil.getRequestParameter("dtable_entity_cls");
		T entity = editableViewModel.getEntity();
		
		List<MappingRelation> relations = getBaseDTPanelController()
				.getQuickJsfContainer().getRelationMap().get(entity.getClass().getSimpleName());
		
		for (MappingRelation mappingRelation : relations) {
			if (mappingRelation.getTargetEntity().getSimpleName().equals(className)) {
				return mappingRelation;
			}
		}
		return null;
	}
}
